package com.smh.hmdianping.controller;

import cn.hutool.core.util.RandomUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.smh.hmdianping.constant.UserConstant;
import com.smh.hmdianping.pojo.Shop;
import com.smh.hmdianping.pojo.ShopType;
import com.smh.hmdianping.vo.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author shiminghui
 * @date 2025/3/27 17:12
 * @description: TODO
 */
@RestController
@RequestMapping("/shop")
public class ShopController {

    private static final ObjectMapper json = new ObjectMapper();
    ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 8, 100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), new ThreadPoolExecutor.DiscardPolicy());
    @Autowired
    private StringRedisTemplate redisTemplate;

    // 获取店铺信息
    @GetMapping("/getShopInfo/{shopId}")
    public ResponseResult getShopInfo(@PathVariable("shopId") Long shopId) {

        // 先查缓存
        String s = redisTemplate.opsForValue().get("hm:shop:" + shopId);
        if (s != null && !s.isEmpty()) {
            try {
                Shop shop = json.readValue(s, Shop.class);
                return ResponseResult.success(shop);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }
        // 查数据库

        Shop shop = new Shop();
        String jsonShop;
        try {
            jsonShop = json.writeValueAsString(shop);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

        // 存入缓存
        redisTemplate.opsForValue().set(UserConstant.SHOP_PREFIX + shopId, jsonShop);
        // 设置过期时间
        redisTemplate.expire("hm:shop:" + shopId, 60 * 60 * 24, java.util.concurrent.TimeUnit.SECONDS);

        return ResponseResult.success(shop);
    }

    @GetMapping("getShopType/all")
    public ResponseResult getShopType() {

        // 查缓存
        List<String> list =
                redisTemplate.opsForList().range("hm:shopType:all", 0, -1);
        if (list != null && !list.isEmpty()) {
            List<ShopType> collect = list.stream().map(s -> {
                try {
                    return json.readValue(s, ShopType.class);
                } catch (JsonProcessingException e) {
                    throw new RuntimeException(e);
                }
            }).toList();
            return ResponseResult.success(collect);
        }

        // 将查询到的数据存入缓存
        List<ShopType> shopTypes = List.of(new ShopType(1L, "美食"), new ShopType(2L, "电影"), new ShopType(3L, "酒店"));
        List<String> stringList = shopTypes.stream().map(s -> {
            try {
                return json.writeValueAsString(s);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }).toList();
        redisTemplate.opsForList().rightPushAll(UserConstant.SHOP_TYPE_PREFIX + "all", stringList);

        return ResponseResult.success(shopTypes);
    }

    @PostMapping("/updateShop")
    @Transactional
    public ResponseResult updateShop(@RequestBody Shop shop) {

        // 修改数据库


        // 删除缓存
        Boolean delete = redisTemplate.delete(UserConstant.SHOP_PREFIX + shop.getId());
        if (!delete) {
            return ResponseResult.fail("删除缓存失败");
        }


        // 延时10秒删除缓存,(也可以将缓存设置失效时间)
        new Thread(() -> {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        return ResponseResult.success("更新成功");
    }

    public ResponseResult getShopById(Long shopId) {
        // 模拟缓存穿透

        // 查询缓存
        String s = redisTemplate.opsForValue().get(UserConstant.SHOP_PREFIX + shopId);
        if (s != null && !s.isEmpty()) {
            if (s.equals("null")) {
                return ResponseResult.fail("店铺不存在");
            }
            try {
                Shop shop = json.readValue(s, Shop.class);
                return ResponseResult.success(shop);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }
        // 查数据库
        Shop shop = new Shop();
        // 有的话
        if (shop != null) {
            try {
                String jsonShop = json.writeValueAsString(shop);
                // 存入缓存
                redisTemplate.opsForValue().set(UserConstant.SHOP_PREFIX + shopId, jsonShop);
                // 设置过期时间
                redisTemplate.expire("hm:shop:" + shopId, 60 * 60 * 24, java.util.concurrent.TimeUnit.SECONDS);
                return ResponseResult.success(shop);
            } catch (JsonProcessingException e) {
            }
        }
        // 没有,存入null
        redisTemplate.opsForValue().set(UserConstant.SHOP_PREFIX + shopId, "null");
        return ResponseResult.fail("店铺不存在");
    }

    public ResponseResult test(Long shopTypeId) {
        // 缓存雪崩

        // 设置key的随机过期时间
        redisTemplate.opsForValue().set(UserConstant.SHOP_TYPE_PREFIX + shopTypeId, "null");
        redisTemplate.expire(UserConstant.SHOP_TYPE_PREFIX + shopTypeId, 60 * 30 + RandomUtil.randomInt(1, 1000), TimeUnit.SECONDS);

        // redis集群

        // 限流
        return ResponseResult.success("成功");
    }

    public ResponseResult test2(Long shopTypeId) {
        // 缓存击穿

        // 先查询缓存
        String s = redisTemplate.opsForValue().get(UserConstant.SHOP_TYPE_PREFIX + shopTypeId);
        if (s != null && !s.isEmpty()) {
            try {
                ShopType shopType = json.readValue(s, ShopType.class);
                return ResponseResult.success(shopType);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }

        // 使用互斥锁
        Boolean b = redisTemplate.opsForValue().setIfAbsent(UserConstant.SHOP_TYPE_PREFIX + shopTypeId, "null", 5, TimeUnit.SECONDS);
        if (b) {
            // 获取锁成功
            // 查询数据库

            // 写入缓存
            redisTemplate.opsForValue().set(UserConstant.SHOP_PREFIX + shopTypeId, "null");

            // 释放锁
            redisTemplate.delete(UserConstant.SHOP_TYPE_PREFIX + shopTypeId);
            return ResponseResult.success("成功");
        } else {
            // 获取锁失败
            int sum = 0;
            while (true) {
                if (sum > 5) {
                    return ResponseResult.fail("失败");
                }
                // 休眠
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                // 重试此方法
                //todo
                sum++;
            }
        }
    }

    public ResponseResult test3(Long shopTypeId) {
        // 缓存击穿
        // 逻辑过期解决
        String s = redisTemplate.opsForValue().get(UserConstant.SHOP_TYPE_PREFIX + shopTypeId);
        // 判断是否过期
        if (s != null && !s.isEmpty()) {
            try {
                ShopType shopType = json.readValue(s, ShopType.class);
//                if (shopType.getExpireTime().isAfter(LocalDateTime.now())){

                // 获取锁

                // 获取成功
//                    // 查询数据库更新缓存
//                    //todo
                // 这里开一个线程更新缓存,以免阻塞(使用缓存池)
                executor.submit(() -> {

                    // 释放锁
                });
                // 返回缓存数据
//                    return ResponseResult.success(shopType);

                // 获取失败
                //直接返回缓存数据
//                }
                return ResponseResult.success(shopType);
            } catch (JsonProcessingException e) {
                throw new RuntimeException();
            }
        }
        return ResponseResult.fail("失败");
    }

}
